import { FilterSpecification } from 'mapbox-gl';
import { Operator } from './operators';
import { OpDecision } from './operators/decision';

type Condition = Operator;

class FilterBuilder {
  combineType: 'any' | 'all';
  private conditions: Condition[] = [];
  private decision = new OpDecision();

  constructor(
    combineType: 'any' | 'all' = 'any',
    conditions: Condition[] = [],
  ) {
    this.combineType = combineType;
    this.addConditions(conditions);
  }

  static any(conditions: Condition[] = []) {
    return new FilterBuilder('any', conditions);
  }
  static all(conditions: Condition[] = []) {
    return new FilterBuilder('all', conditions);
  }

  addConditions(conditions: Condition | Condition[]) {
    if (!Array.isArray(conditions)) {
      conditions = [conditions];
    }
    this.conditions.push(...conditions);
    return this;
  }

  format(): FilterSpecification {
    const filter = this.conditions.map((condition) => {
      const { operator, property, value } = condition;
      return [operator, property, value];
    });
    return [this.combineType, ...filter];
  }

  // decision
  equal(property: string, value: string | number | boolean) {
    const condition = this.decision.equal(property, value) as Operator;
    return this.addConditions(condition);
  }
  notEqual(property: string, value: string | number | boolean) {
    const condition = this.decision.notEqual(property, value) as Operator;
    return this.addConditions(condition);
  }
  greaterThan(property: string, value: string | number | boolean) {
    const condition = this.decision.greaterThan(property, value) as Operator;
    return this.addConditions(condition);
  }
  greaterThanOrEqual(property: string, value: string | number | boolean) {
    const condition = this.decision.greaterThanOrEqual(
      property,
      value,
    ) as Operator;
    return this.addConditions(condition);
  }
  lessThan(property: string, value: string | number | boolean) {
    const condition = this.decision.lessThan(property, value) as Operator;
    return this.addConditions(condition);
  }
  lessThanOrEqual(property: string, value: string | number | boolean) {
    const condition = this.decision.lessThanOrEqual(
      property,
      value,
    ) as Operator;
    return this.addConditions(condition);
  }
}

export { FilterBuilder };
